<?php
namespace app\core\entities;

use app\core\events\EventTrait;
use app\core\AggregateRoot;
use DomainException;
use Ramsey\Uuid\Uuid;
use Yii;
use yii\base\Exception;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\UploadedFile;
//use zertex\avatar_generator\AvatarGenerator;

/**
 * User model
 *
 * @property string $id
 * @property string $username
 * @property string $password_hash
 * @property string $password_reset_token
 * @property string $email
 * @property string $email_confirm_token
 * @property string $auth_key
 * @property integer $status
 * @property integer $created_at
 * @property integer $updated_at
 * @property string|UploadedFile $user_pic
 * @property string $allowance [integer]
 * @property string $allowance_updated_at [integer]
 * @property string $settings [jsonb]
 * @property string $factor2_use [integer]
 * @property string $factor2_code [varchar(255)]
 */
class User extends ActiveRecord implements AggregateRoot
{
    use EventTrait;

    const STATUS_WAIT = 0;
    const STATUS_ACTIVE = 10;

    /**
     * @throws Exception
     */
    public static function create(string $username, string $email, string $password): self
    {
        $user           = new User();
        $user->id       = Uuid::uuid4();
        $user->username = $username;
        $user->email    = $email;
        $user->setPassword(!empty($password) ? $password : Yii::$app->security->generateRandomString());
        $user->created_at = time();
        $user->status     = self::STATUS_ACTIVE;
        $user->auth_key   = Yii::$app->security->generateRandomString();

//        if ($user->user_pic) {
//            $fileName = md5('avatar-' . $user->user_pic->baseName . time()) . '.' . $user->user_pic->extension;
//            if ($user->user_pic->saveAs((new AvatarGenerator())->getPath('avatar') . '/' . $fileName)) {
//                $user->user_pic = $fileName;
//            }
//        }

        return $user;
    }

    /**
     * @throws Exception
     */
    public function edit(string $username, string $email, string $password, $user_pic = null): void
    {
        $this->username   = $username;
        $this->email      = $email;
        $this->updated_at = time();

//        if ($user_pic) {
//            $fileName = md5('avatar-' . $user_pic->baseName . time()) . '.' . $user_pic->extension;
//            if ($user_pic->saveAs((new AvatarGenerator())->getPath('avatar') . '/' . $fileName)) {
//                (new AvatarGenerator())->remove('avatar', $this->user_pic);
//                $this->user_pic = $fileName;
//            }
//        }

        if ($password) {
            $this->setPassword(!empty($password) ? $password : Yii::$app->security->generateRandomString());
            $this->generateAuthKey();
        }
    }

//    public function editAvatar($user_pic): void
//    {
//        if ($user_pic) {
//            $fileName = md5('avatar-' . $user_pic->baseName . time()) . '.' . $user_pic->extension;
//            $path     = Yii::getAlias('@runtime/' . $fileName);
//            $user_pic->saveAs($path);
//            $this->user_pic = basename(Yii::$app->avatar->update($this->username . '_' . $this->id, null, $path));
//            if (file_exists($path)) {
//                unlink($path);
//            }
//        }
//    }

    /**
     * @throws Exception
     */
    public function editProfile(
        string $username,
        string $password = null
    ): void {
        //$this->email    = $email;
        $this->username = $username;
        if ($password) {
            $this->setPassword($password);
        }
        $this->updated_at = time();
    }

    /**
     * @throws Exception
     */
    public static function requestSmartSignup(string $email): self
    {
        $password = Yii::$app->security->generateRandomString(10);

        $parts = explode('@', $email);

        $user                       = new User();
        $user->username             = is_array($parts) && isset($parts[0]) ? $parts[0] : 'Member';
        $user->email                = $email;
        $user->setPassword($password);
        $user->created_at           = time();
        $user->status               = self::STATUS_WAIT;
        $user->email_confirm_token  = null;
        $user->generateAuthKey();
        //$user->recordEvent(new UserSmartSignUpRequested($user, $password, Yii::$app->language, $franchise_path));
        //$user->temp_password = $password;

        return $user;
    }

    public function confirmSignup(): void
    {
        if (!$this->isWait()) {
            throw new DomainException('User is already active.');
        }
        $this->status              = self::STATUS_ACTIVE;
        $this->email_confirm_token = null;
        //$this->recordEvent(new UserSignUpConfirmed($this));
    }

    public function requestPasswordReset(): void
    {
        if (!empty($this->password_reset_token) && self::isPasswordResetTokenValid($this->password_reset_token)) {
            $timestamp = (int)substr($this->password_reset_token, strrpos($this->password_reset_token, '_') + 1);
            if ($timestamp + 5 * 60 > time()) {
                throw new DomainException(Yii::t('auth', 'Password resetting is already requested. Repeat the request in {min} sec.', ['min' => 5 * 60 - (time() - $timestamp)]), 10201);
            }
        }

        try {
            $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
        } catch (Exception $e) {
            $this->password_reset_token = '234543n2jn0jjJMm1mf0ds0oos0re0sf123_' . time();
        }
    }

    public function resetPassword($password): void
    {
        if (empty($this->password_reset_token)) {
            throw new DomainException('Password resetting is not requested.');
        }
        try {
            $this->setPassword($password);
            $this->password_reset_token = null;
        } catch (Exception $e) {
            throw new DomainException('Password reset failed.');
        }
    }

    public function isWait(): bool
    {
        return $this->status === self::STATUS_WAIT;
    }

    public function isActive(): bool
    {
        return $this->status === self::STATUS_ACTIVE;
    }

    /**
     * @inheritdoc
     */
    public static function tableName(): string
    {
        return '{{%users}}';
    }

    /**
     * @inheritdoc
     */
    public function behaviors(): array
    {
        return [
            TimestampBehavior::class,
        ];
    }

    public function transactions(): array
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }

    public function usedFactor2(): bool
    {
        return $this->factor2_use == 1;
    }

    /**
     * Finds user by password reset token
     *
     * @param string $token password reset token
     *
     * @return User|null
     */
    public static function findByPasswordResetToken(string $token): ?static
    {
        if (!static::isPasswordResetTokenValid($token)) {
            return null;
        }

        return static::findOne([
            'password_reset_token' => $token,
        ]);
    }

    /**
     * Finds out if password reset token is valid
     *
     * @param string $token password reset token
     *
     * @return bool
     */
    public static function isPasswordResetTokenValid(string $token): bool
    {
        if (empty($token)) {
            return false;
        }

        $timestamp = (int)substr($token, strrpos($token, '_') + 1);
        $expire    = Yii::$app->params['user.passwordResetTokenExpire'];

        return $timestamp + $expire >= time();
    }

    /**
     * Validates password
     *
     * @param string $password password to validate
     *
     * @return bool if password provided is valid for current user
     */
    public function validatePassword(string $password): bool
    {
        return Yii::$app->security->validatePassword($password, $this->password_hash);
    }

    /**
     * @param $password
     *
     * @throws Exception
     */
    private function setPassword($password): void
    {
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
    }

    /**
     * Generates "remember me" authentication key
     * @throws Exception
     */
    public function generateAuthKey(): void
    {
        $this->auth_key = Yii::$app->security->generateRandomString();
    }
}
